package com.ly.user_system.base;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ly.user_system.common.PageResult;
import com.ly.user_system.utils.ConvertUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author HASEE
 */
public class BaseServiceImpl<Entity, Detail, DTO, PQuery extends PageQuery, M extends BaseMapper<Entity>> extends ServiceImpl<M, Entity> implements BaseService<Entity, DTO, Detail, PQuery>, IService<Entity> {

    private M baseMapper;

    private Class<DTO> dtoClass;

    private Class<Entity> entityClass;

    private Class<Detail> detailClass;


    // 哪些字段可以参与查询
    private final HashMap<SelectType, Set<String>> queryFiledMap = new HashMap<>(SelectType.values().length);

    public BaseServiceImpl() {
        init(entityClass, dtoClass, detailClass, detailFunction);
    }


    // 详情数据消费
    private Function<Entity, Detail> detailFunction;



    @Autowired
    public void setBaseMapper(M baseMapper) {
        this.baseMapper = baseMapper;
    }


    /**
     * 初始化数据信息以及相关字段的查询信息
     * 初始化实体类以及dto，详情和自定义转换的详情组装方法
     * 哪些字段需要加入到查询列表中,todo 后续改造成前后端分离处理
     */
    protected void init(Class<Entity> entityClass, Class<DTO> dtoClass, Class<Detail> detailClass, Function<Entity, Detail> detailFunction) {
        this.entityClass = entityClass;
        this.dtoClass = dtoClass;
        this.detailFunction = detailFunction;
        this.detailClass = detailClass;
        Arrays.stream(entityClass.getDeclaredFields())
                .filter(field -> AnnotationUtils.getAnnotation(field, SelectFiled.class) != null)
                .forEach(field -> {
                    SelectFiled annotation = field.getAnnotation(SelectFiled.class);
                    SelectType[] types = annotation.types();
                    if (ArrayUtil.isNotEmpty(types)) {
                        TableField tableField = AnnotationUtils.getAnnotation(field, TableField.class);
                        Arrays.stream(types).forEach(type -> queryFiledMap.computeIfAbsent(type, k -> new HashSet<>())
                                .add(tableField == null ? StrUtil.toUnderlineCase(field.getName()) : tableField.value()));
                    }
                });
    }


    @Override
    public Boolean saveBatch(List<DTO> list) {
        List<Entity> dataList = ConvertUtil.convert(list, entityClass);
        return this.saveOrUpdateBatch(dataList, dataList.size());
    }

    @Override
    public Boolean saveBatch(List<DTO> dtos, Consumer<List<Entity>> entityConsumer) {
        List<Entity> dataList = ConvertUtil.convert(dtos, entityClass);
        this.saveOrUpdateBatch(dataList, dataList.size());
        entityConsumer.accept(dataList);
        return true;
    }



    @Override
    public  List<DTO> list(DTO dto) {
        return ConvertUtil.convert(this.baseMapper.selectList(fillQuery(BeanUtil.beanToMap(dto, true, true))), dtoClass);
    }


    @Override
    public PageResult<DTO> page(PQuery query) {
        // 去除所有空格自负床
        BeanUtil.trimStrFields(query);
        Page<Entity> page = new Page<>(query.getCurrentPage(), query.getPageSize());
        Page<Entity> p = baseMapper.selectPage(page, fillQuery(BeanUtil.beanToMap(query, true, true)));
        if (p.getRecords().isEmpty()) {
            return new PageResult<>(null, p.getCurrent(), p.getSize(), p.getPages());
        }
        // 实体列表属性先转换成返回类型，再进行消费组装返回
        return new PageResult<>(ConvertUtil.convert(p.getRecords(), dtoClass), p.getCurrent(), p.getSize(), p.getTotal());
    }

    private QueryWrapper<Entity> fillQuery(Map<String,Object> paramMap){
        BeanUtil.trimStrFields(paramMap);
        QueryWrapper<Entity> queryWrapper = new QueryWrapper<>();
        // 根据查询字段进行填充查询条件
        queryFiledMap.forEach((queryType, fields) ->
                fields.stream()
                        .parallel()
                        .filter(field -> paramMap.containsKey(field) && ObjectUtil.isNotEmpty(paramMap.get(field)))
                        .forEach(field -> {
                            Object value = paramMap.get(field);
                            switch (queryType) {
                                case eq -> queryWrapper.eq(field, value);
                                case like -> queryWrapper.like(field, value);
                                case rightLike -> queryWrapper.likeRight(field, value);
                                case orderBy -> queryWrapper.orderByDesc(field);
                                default -> throw new IllegalArgumentException("不支持的查询类型: " + queryType);
                            }
                        })
        );
        return queryWrapper;
    }


    @Override
    public Boolean update(DTO dto) {
        return this.updateById(ConvertUtil.convert(dto, entityClass));
    }

    @Override
    public Boolean batchUpdate(List<DTO> list) {
        List<Entity> dataList = ConvertUtil.convert(list, entityClass);
        return this.saveOrUpdateBatch(dataList, dataList.size());
    }


    @Override
    public Boolean deleteBatch(List<Long> ids) {
        return this.removeBatchByIds(ids);
    }

    @Override
    public Boolean deleteBatch(List<Long> ids, Consumer<List<Long>> checkConsumer) {
        checkConsumer.accept(ids);
        this.deleteBatch(ids);
        return true;
    }


    @Override
    public DTO getById(Long id) {
        return getByIds(List.of(id)).get(0);
    }

    @Override
    public List<DTO> getByIds(List<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return new ArrayList<>();
        }
        List<Entity> entities = baseMapper.selectByIds(ids);
        return ConvertUtil.convert(entities, dtoClass);
    }

    @Override
    public Detail detailById(Long id) {
        return ConvertUtil.convert(baseMapper.selectById(id), detailClass);
    }

    @Override
    public List<DTO> listDtoWithConsumer(Consumer<LambdaQueryWrapper<Entity>> queryWrapperConsumer, Function<List<DTO>,List<DTO>> function) {
        List<Entity> entityList = listEntity(queryWrapperConsumer);
        List<DTO> dtoList = ConvertUtil.convert(entityList, dtoClass);
        if (CollUtil.isEmpty(dtoList)){
            return new ArrayList<>();
        }
        return function.apply(dtoList);
    }

    @Override
    public <T> T queryEntityWithFunction(Consumer<LambdaQueryWrapper<Entity>> queryWrapperConsumer, Function<Entity, T> function) {
        return listEntityWithFunction(queryWrapperConsumer, function).get(0);
    }

    @Override
    public Entity queryEntity(Consumer<LambdaQueryWrapper<Entity>> queryWrapperConsumer) {
        LambdaQueryWrapper<Entity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapperConsumer.accept(queryWrapper);
        return baseMapper.selectOne(queryWrapper);
    }

    @Override
    public List<Entity> listEntity(Consumer<LambdaQueryWrapper<Entity>> queryWrapperConsumer) {
        LambdaQueryWrapper<Entity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapperConsumer.accept(queryWrapper);
        return baseMapper.selectList(queryWrapper);
    }

    @Override
    public <T> List<T> listEntityWithFunction(Consumer<LambdaQueryWrapper<Entity>> queryWrapperConsumer, Function<Entity, T> function) {
        return listEntity(queryWrapperConsumer)
                .stream()
                .map(function)
                .collect(Collectors.toList());
    }


}
